package itb.fhv.sa.pipesfilters;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Class for reading data from an input source. This class is the first element
 * in the pipeline.
 * 
 * @date Oct 17, 2008
 * @author Malcolm Staudacher
 * 
 */
public class DataSource extends Filter {

	private BufferedReader m_input;


	public DataSource(Pipe neighbour, InputStreamReader in) {
		super(neighbour);
		m_neighbour1 = neighbour;
		m_input = new BufferedReader(in);
	}


	// for pull pipelines
	public DataSource(InputStreamReader in) {
		m_input = new BufferedReader(in);
	}


	/**
	 * Reads characters from an input source.
	 * 
	 * @return A Character object from the read character.
	 */
	@Override
	public PLOutput read() {
		int ch = 0;
		Character result = null;

		if (m_input != null) {

			try {
				ch = m_input.read();

				if (ch != -1) { // detect the end of the data
					result = new Character((char) ch);
				} else {
					result = new Character('\1');
				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

		return result;
	}


	/**
	 * This method is not used at this time.
	 */
	@Override
	public boolean write(PLOutput plo) {
		return false;
	}


	/**
	 * Method for writing to the pipeline if this is a push pipeline. This
	 * method reads the data from an input source and pushes it into the
	 * pipeline.
	 */
	public void write() {
		int ch = 0;
		boolean written = false;

		if (m_input != null && m_neighbour1 != null) {

			while (ch != -1) {

				try {
					ch = m_input.read();

					if (ch != -1) {

						// keep trying to write, until data is successfully
						// written to the next element
						while (written == false) {
							written = m_neighbour1.write(new Character(
									(char) ch));
						}

						written = false;
					}

				} catch (IOException e) {
					e.printStackTrace();
				}

			}

			// when the end of the data is reached, flush the pipeline.
			flush();
		}

	}


	@Override
	public void flush() {
		m_neighbour1.flush();
	}

}
